﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

using TraitorAmongUs.Common;
using TraitorAmongUs.Network;

namespace TraitorAmongUs.States {
	public class LobbyState : Singleton<LobbyState>, GameState {
		Engine engine;

		Nuclex.UserInterface.Controls.LabelControl testLabel;
		Nuclex.UserInterface.Controls.Desktop.ButtonControl startButton;
		Nuclex.UserInterface.Controls.Desktop.ListControl lobbyChat;
		Nuclex.UserInterface.Controls.Desktop.InputControl lobbySendChat;

		bool isHostingGame = false;

		public LobbyState() {
		}

		void GameState.EnterState(Engine e, dynamic param) {
			engine = e;

			engine.SetCursorVisibility(true);

			// Get the parameters
			var Param_Hosting = (param.GetType().GetProperty("Hosting") != null ? param.Hosting : false);
			var Param_ServerHost = (param.GetType().GetProperty("ServerHost") != null ? param.ServerHost : "localhost");
			var Param_ServerPort = (param.GetType().GetProperty("ServerPort") != null ? param.ServerPort : 1337);
			var Param_Connected = (param.GetType().GetProperty("Connected") != null ? param.Connected : false);

			if(!Param_Connected) {
				isHostingGame = Param_Hosting;

				// Start the game server if it's not already running
				if(isHostingGame) {
					if(engine.gameServer == null) {
						engine.gameServer = new Network.Server();
						engine.gameServer.Run(Param_ServerPort);
					}
				}

				// Connect to the server
				engine.networkClient = new Network.Client();
				engine.networkClient.ConnectToServer(Param_ServerHost, Param_ServerPort);

				if(isHostingGame) {
					// Send the "set host" packet
					using(Packet packet = new Packet()) {
						packet.Send(engine.networkClient.Stream, Packet.PacketTypes.SERVER_LOBBY_SET_HOST);
					}
				}
			}

			// Hook the events
			engine.networkClient.OnServerFullPacketReceived += new Client.ServerFullPacketReceivedHandler(networkClient_OnServerFullPacketReceived);
			engine.networkClient.OnVersionPacketReceived += new Network.Client.VersionPacketReceivedHandler(networkClient_OVersionPacketReceived);
			engine.networkClient.OnChatPacketReceived += new Network.Client.ChatPacketReceievedHandler(networkClient_OnChatPacketReceived);
			engine.networkClient.OnStartGamePacketReceived += new Network.Client.StartGameReceivedHandler(networkClient_OnStartGamePacketReceived);

			// Create the Lobby GUI
			testLabel = new Nuclex.UserInterface.Controls.LabelControl("Lobby");
			testLabel.Bounds = new Nuclex.UserInterface.UniRectangle(10.0f, 15.0f, 110.0f, 30.0f);
			engine.guiManager.Screen.Desktop.Children.Add(testLabel);

			lobbyChat = new Nuclex.UserInterface.Controls.Desktop.ListControl();
			lobbyChat.Bounds = new Nuclex.UserInterface.UniRectangle(10.0f, 50.0f, 600.0f, 300.0f);
			lobbyChat.SelectionMode = Nuclex.UserInterface.Controls.Desktop.ListSelectionMode.None;
			lobbyChat.Slider.ThumbPosition = 1.0f;
			engine.guiManager.Screen.Desktop.Children.Add(lobbyChat);

			lobbySendChat = new Nuclex.UserInterface.Controls.Desktop.InputControl();
			lobbySendChat.Bounds = new Nuclex.UserInterface.UniRectangle(10.0f, 350.0f, 600.0f, 30.0f);
			engine.guiManager.Screen.Desktop.Children.Add(lobbySendChat);

			startButton = new Nuclex.UserInterface.Controls.Desktop.ButtonControl();
			startButton.Bounds = new Nuclex.UserInterface.UniRectangle(10.0f, 400.0f, 110.0f, 30.0f);
			startButton.Text = "Start Game";
			startButton.Pressed += new EventHandler(startButton_Pressed);
			engine.guiManager.Screen.Desktop.Children.Add(startButton);


			// Handle the enter button being pressed to send lobby chat
			engine.inputManager.GetKeyboard().KeyPressed += new Nuclex.Input.Devices.KeyDelegate(LobbyState_KeyPressed);
		}

		void LobbyState_KeyPressed(Keys key) {
			if(key == Keys.Enter) {
				if(lobbySendChat.HasFocus && !string.IsNullOrWhiteSpace(lobbySendChat.Text)) {
					using(Packet packet = new Packet()) {
						packet.Write(lobbySendChat.Text);
						packet.Send(engine.networkClient.Stream, Packet.PacketTypes.SERVER_LOBBY_CHATMESSSAGE);
					}

					lobbySendChat.Text = "";
				}
			}
		}

		void startButton_Pressed(object sender, EventArgs e) {
			// Change the state
			//engine.stateManager.SetState(States.PlayingState.Instance, null);

			if(isHostingGame) {
				// Send the "start game" packet
				using(Packet packet = new Packet()) {
					packet.Send(engine.networkClient.Stream, Packet.PacketTypes.SERVER_LOBBY_START_GAME);
				}
			}
		}

		void GameState.LeaveState() {
			// Unhook the packet events
			engine.networkClient.OnServerFullPacketReceived -= new Client.ServerFullPacketReceivedHandler(networkClient_OnServerFullPacketReceived);
			engine.networkClient.OnVersionPacketReceived -= new Network.Client.VersionPacketReceivedHandler(networkClient_OVersionPacketReceived);
			engine.networkClient.OnChatPacketReceived -= new Network.Client.ChatPacketReceievedHandler(networkClient_OnChatPacketReceived);
			engine.networkClient.OnStartGamePacketReceived -= new Network.Client.StartGameReceivedHandler(networkClient_OnStartGamePacketReceived);

			// Unload the GUI
			engine.guiManager.Screen.Desktop.Children.Clear();

			// Detach the keypressed event
			engine.inputManager.GetKeyboard().KeyPressed -= new Nuclex.Input.Devices.KeyDelegate(LobbyState_KeyPressed);
		}

		void GameState.Draw(GameTime gameTime) {
			engine.GraphicsDevice.Clear(Color.Beige);
		}

		void GameState.Update(GameTime gameTime) {
		}



		// Packet Events
		void networkClient_OnServerFullPacketReceived() {
			System.Windows.Forms.MessageBox.Show("Server is full");

			engine.stateManager.SetState(States.MainMenuState.Instance, null);
		}

		void networkClient_OVersionPacketReceived() {
		}

		void networkClient_OnChatPacketReceived(string username, string message) {
			bool scrollToBottom = (lobbyChat.Slider.ThumbPosition == 1.0f);

			lobbyChat.Items.Add(string.Format("<{0}> {1}", username, message));

			if(scrollToBottom) {
				lobbyChat.Slider.ThumbPosition = 1.0f;
			}
		}

		void networkClient_OnStartGamePacketReceived() {
			engine.stateManager.SetState(States.PlayingState.Instance, null);
		}
	}
}